import { IDatasetExportPolicy } from '@datahub/metadata-types/types/entity/dataset/compliance/export-policy';
import { alias } from '@ember/object/computed';
import { setProperties } from '@ember/object';
import { Omit, omit } from 'lodash';
import { arrayEvery } from '@datahub/utils/array/every';
import { computed } from '@ember/object';

/**
 * Gives us a blank default value for the working copy if none is provided by the API layer
 */
const DatasetExportPolicyFactory = (): IDatasetExportPolicy => ({
  containsUserActionGeneratedContent: null,
  containsUserDerivedContent: null,
  containsUserGeneratedContent: null,
  modifiedBy: null,
  modifiedTime: null
});

/**
 * A classified version of the dataset export policy API return. This serves as the data layer
 * intermediary between the actual API response and the UI layer, making any transformations
 * necessary to simplify the response into a consumable format
 */
export class DatasetExportPolicy {
  /**
   * Original API data retrieved for this class. Stored here to power our working copy of the
   * export policy
   * @type {IDatasetExportPolicy}
   * @memberof DatasetExportPolicy
   */
  readonly data: IDatasetExportPolicy;

  /**
   * Whether the dataset contains content generated by user action
   * @type {boolean}
   * @memberof DatasetExportPolicy
   */
  containsUserActionGeneratedContent!: boolean | null;

  /**
   * Whether the dataset contains content derived from user information
   * @type {boolean}
   * @memberof DatasetExportPolicy
   */
  containsUserDerivedContent!: boolean | null;

  /**
   * Whether the dataset contains user generated content
   * @type {boolean}
   * @memberof DatasetExportPolicy
   */
  containsUserGeneratedContent!: boolean | null;

  /**
   * username of who last modified this policy
   * @type {string}
   * @memberof DatasetExportPolicy
   */
  @alias('data.modifiedBy')
  modifiedBy!: string;

  /**
   * Unix timestamp for last modified date/time
   * @type {number}
   * @memberof DatasetExportPolicy
   */
  @alias('data.modifiedTime')
  modifiedTime!: number;

  /**
   * Returns whether all the editable items in the export policy are currently not defined (or null)
   * @type {boolean}
   * @memberof DatasetExportPolicy
   */
  @computed('data')
  get isEmpty(): boolean {
    const { data } = this;
    const exportPolicyKeys = Object.keys(omit(data, ['modifiedBy', 'modifiedTime'])) as Array<
      keyof IDatasetExportPolicy
    >;

    return arrayEvery((key: keyof IDatasetExportPolicy) => data[key] === null)(exportPolicyKeys);
  }

  /**
   * Creates or resets the working copy for the export policy of a dataset. Using this method,
   * we can initially initialize our desired properties from the original data, or revert any
   * changes back to that data
   */
  createWorkingCopy(): void {
    const {
      data: {
        containsUserActionGeneratedContent = null,
        containsUserDerivedContent = null,
        containsUserGeneratedContent = null
      }
    } = this;

    setProperties(this, {
      containsUserActionGeneratedContent,
      containsUserDerivedContent,
      containsUserGeneratedContent
    });
  }

  /**
   * Creates an API friendly object from our classified working copy.
   */
  readWorkingCopy(): Omit<IDatasetExportPolicy, 'modifiedTime' | 'modifiedBy'> {
    const {
      containsUserActionGeneratedContent = null,
      containsUserDerivedContent = null,
      containsUserGeneratedContent = null
    } = this;

    return {
      containsUserActionGeneratedContent,
      containsUserDerivedContent,
      containsUserGeneratedContent
    };
  }

  constructor(exportPolicyData: IDatasetExportPolicy = DatasetExportPolicyFactory()) {
    this.data = exportPolicyData;
    this.createWorkingCopy();
  }
}
